﻿using System;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using CalcSharp.Core;
using CalcSharp.Properties;
using CalcSharp.Ui;
using dnAnalytics.Math;

namespace CalcSharp.MDIUI
{
    public partial class ConsoleFrm : Form
    {
        private Color forecolor;
        private Point reset;
        private paramcomp p;
        private Thread T;
        private bool reroute;
        private int controll;
        private HistoryWindow HistroyWin;
        private DateTime start, stop;
        private TimeSpan diff;


        public delegate void SimpleCall();
        public delegate void WriteCall(string text);
        public delegate void ColorSetCall(Color C);

        public ConsoleFrm()
        {
            InitializeComponent();
            cmdbox.AutoCompleteCustomSource.AddRange(Program.supported);
            cmdbox.AutoCompleteCustomSource.AddRange(Program.loaded.PluginCommands);
            this.ActiveControl = cmdbox;
            try
            {
                XMLMenu x = new XMLMenu("consolemenu.xml", this.consolemenu);
            }
            catch (Exception ex)
            {
                MessageBox.Show("The folowing error occured:\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            reset = new Point(this.Width, this.Height);
            this.forecolor = Settings.Default.console_color;
            this.HistroyWin = new HistoryWindow();
            this.HistroyWin.TopMost = true;
            this.HistroyWin.TopLevel = false;
            this.HistroyWin.Parent = this;
        }

        public void ShowHistory()
        {
            if (!this.HistroyWin.Visible) this.HistroyWin.Show();
        }

        public void AddCmdBoxText(string str)
        {
            this.cmdbox.AppendText(str);
        }

        public void FocusInput()
        {
            this.cmdbox.Focus();
        }

        public void WriteLine(string input)
        {
            this.Write(input + "\n");
        }

        public void Write(string input)
        {
            if (!reroute && T != null)
            {
                if (this.T.IsAlive)
                {
                    reroute = true;
                    this.Invoke(new WriteCall(Write), new object[] { input });
                }
            }
            else if (this.InvokeRequired)
            {
                reroute = true;
                this.Invoke(new WriteCall(Write), new object[] { input });
            }
            else
            {
                this.Consoletext.SelectionStart = Consoletext.Text.Length > 0 ? Consoletext.Text.Length : 0;
                Consoletext.SelectionColor = this.forecolor;
                Consoletext.SelectedText = input;
                this.reroute = false;
            }
        }

        public void Clear()
        {
            if (!reroute && T != null)
            {
                if (this.T.IsAlive)
                {
                    reroute = true;
                    this.Invoke(new SimpleCall(Clear));
                }
            }
            else if (this.InvokeRequired)
            {
                reroute = true;
                this.Invoke(new SimpleCall(Clear));
            }
            else
            {
                Consoletext.Clear();
                this.reroute = false;
                this.ForegroundColor = Settings.Default.console_textok;
            }
        }

        public void ColorSet(Color C)
        {
            this.forecolor = C;
            this.reroute = false;
        }

        public Color ForegroundColor
        {
            set
            {
                if (!reroute && T != null)
                {
                    if (this.T.IsAlive)
                    {
                        reroute = true;
                        this.Invoke(new ColorSetCall(ColorSet), new object[] { value });
                    }
                }
                else if (this.InvokeRequired)
                {
                    reroute = true;
                    this.Invoke(new ColorSetCall(ColorSet), new object[] { value });
                }
                else this.forecolor = value;
            }
            get
            {
                return this.forecolor;
            }
        }

        private void cmdbox_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Enter:
                    this.DoEnter();
                    break;
                case Keys.Down:
                    cmdbox.Text = HistroyWin.GetNextCommand();
                    break;
                case Keys.Up:
                    cmdbox.Text = HistroyWin.GetPreviousCommand(); 
                    break;
            }
        }

        public void ExecOneCommand(string cmdline)
        {
            this.cmdbox.Text = cmdline;
            this.DoEnter();
        }

        private void InputDisable()
        {
            this.cmdbox.Enabled = false; //no input, amíg processing van...
        }

        private void CalculationDone()
        {
            string modstring = "";
            if (Program.mode == CalculatorModes.Deg) modstring = "(DEG)";
            else if (Program.mode == CalculatorModes.Rad) modstring = "(RAD)";
            else if (Program.mode == CalculatorModes.Grad) modstring = "(GRAD)";
            else if (Program.mode == CalculatorModes.CPLX) modstring = "(CPLX)";
            modedisplay.Text = "Calc# " + modstring + ">";
            this.writeResults();
            this.Consoletext.ScrollToCaret();
            this.cmdbox.Enabled = true;
            this.ActiveControl = cmdbox;
            cmdbox.Focus();
            this.T = null;

            stop = DateTime.Now;
            ((Parentform)Program.loaded.Parent).AnimateProgress(false);
            diff = stop - start;
            ((Parentform)Program.loaded.Parent).UpdateProgressTime(diff);
        }

        private void ThreadFunction()
        {
            try
            {
                this.Invoke(new SimpleCall(InputDisable));
                Program.result = Program.callfunc(controll, true);
                this.Invoke(new SimpleCall(CalculationDone));
            }
            catch (Exception) { CalculationDone(); }
        }

        public void DoEnter()
        {
            this.HistroyWin.AddHistoryItem(cmdbox.Text);
            this.WriteLine(modedisplay.Text + cmdbox.Text);
            Program.cmds = MiscCoreFuncts.split(cmdbox.Text, false);
            string cmdtoexec = Program.cmds[0].ToUpper();
            cmdbox.Clear();
            if (Program.cmds.Length > 0)
            {
                start = DateTime.Now;
                ((Parentform)Program.loaded.Parent).AnimateProgress(true);
                controll = Program.analize(Program.cmds[0]);
                if (controll != -1)
                {
                    if (!ConstCommands.NonThreadCommands.Contains(cmdtoexec) && !Program.loaded.WindowPlugins.Contains(cmdtoexec))
                    {
                        this.T = new Thread(ThreadFunction);
                        T.Start();
                        this.reroute = false;
                    }
                    else
                    {
                        this.InputDisable();
                        Program.result = Program.callfunc(controll, true);
                        this.CalculationDone();
                    }
                }
                else
                {
                    Program.ConsoleForm.ForegroundColor = Settings.Default.console_err;
                    Program.ConsoleForm.WriteLine(" " + Program.cmds[0] + " - Unknown function");
                    Program.ConsoleForm.ForegroundColor = Settings.Default.console_color;
                    Program.loaded.parent.AnimateProgress(false);
                }
                this.cmdbox.Focus();
            }
        }

        public void writeResults()
        {
            this.ForegroundColor = Settings.Default.console_textok;
            if (!double.IsNaN(Program.result.floatingpt))
            {
                Program.loaded.Mem["$lastres"] = Program.result.floatingpt;
                if (Program.result.floatingpt == 1) this.WriteLine(" Result: " + Program.result.floatingpt.ToString() + " (TRUE)\n");
                else if (Program.result.floatingpt == 0) this.WriteLine(" Result: " + Program.result.floatingpt.ToString() + " (FALSE)\n");
                else if (Settings.Default.thousand_grouping) Program.ConsoleForm.WriteLine(" Result: " + MiscCoreFuncts.FormatDouble(Program.result.floatingpt) + "\n");
                else Program.ConsoleForm.WriteLine(" Result: " + Program.result.floatingpt.ToString() + "\n");
                Program.loaded.Flags.SetRegister(Program.result.floatingpt);
            }
            else if (Program.result.matrixtype != null)
            {
                this.WriteLine(" Result Matrix saved as #last_mtrx");
                Program.loaded.Mtrx_mem["#last_mtrx"] = Program.result.matrixtype;
                Program.loaded.Flags.SetRegister(Program.result.matrixtype);
            }
            else if (!Complex.IsNaN(Program.result.complex))
            {
                this.WriteLine(" Result: " + Program.result.complex.ToString());
                Program.loaded.CPLX_mem["&last_cplx"] = Program.result.complex;
                Program.loaded.Flags.SetRegister(Program.result.complex);
            }
            else if (Program.result.settype != null)
            {
                StringBuilder s = new StringBuilder();
                for (int i = 0; i < Program.result.settype.Count; i++) s.Append(Program.result.settype[i] + "; ");
                this.WriteLine(" Result Set items: " + s.ToString());
                Program.loaded.Set_mem["@last_set"] = Program.result.settype;
                Program.loaded.Flags.SetRegister(Program.result.settype);
            }
            else if (!string.IsNullOrEmpty(Program.result.stringtype))
            {
                this.WriteLine(" Result string: " + Program.result.stringtype);
                Program.loaded.String_mem["~last_string"] = Program.result.stringtype;
                Program.loaded.Flags.SetRegister(Program.result.stringtype);
            }
            this.ForegroundColor = Settings.Default.console_color;
            ((Parentform)Program.loaded.Parent).UpdateMemoryMap(CalcSharp.MDIUI.ToolBars.mMapSegment.mAll);
        }

        private void ConsoleFrm_Click(object sender, EventArgs e)
        {
            this.ActiveControl = cmdbox;
        }

        private void Consoletext_KeyPress(object sender, KeyPressEventArgs e)
        {
            this.ActiveControl = cmdbox;
        }

        private void ConsoleFrm_Load(object sender, EventArgs e)
        {
            string modstring = "";
            if (Program.mode == CalculatorModes.Deg) modstring = "(DEG)";
            else if (Program.mode == CalculatorModes.Rad) modstring = "(RAD)";
            modedisplay.Text = "Calc# " + modstring + ">";
        }

        private void ConsoleFrm_Resize(object sender, EventArgs e)
        {
            try
            {
                splitContainer1.SplitterDistance = (splitContainer1.Height - splitContainer1.Panel2MinSize + 10);
            }
            catch { ; }
        }

        private void saveConsoleTextToolStripMenuItem_Click(object sender, EventArgs e)
        {
            savelogdlg.ShowDialog();
            if (!string.IsNullOrEmpty(savelogdlg.FileName))
            {
                Program.ConsoleForm.Consoletext.SaveFile(savelogdlg.FileName, RichTextBoxStreamType.RichText);
            }
        }

        private void ConsoleFrm_FormClosing(object sender, FormClosingEventArgs e)
        {
            
        }

        void it_Click(object sender, EventArgs e)
        {
            cmdbox.AppendText((sender as ToolStripItem).Text);
        }

        private void exitProgramToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void cmdbox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Tab && e.Modifiers == Keys.None)
            {
                if (!string.IsNullOrEmpty(cmdbox.Text))
                {
                    p = new paramcomp();
                    p.TopMost = true;
                    p.TopLevel = false;
                    p.Parent = this;
                    p.Top = this.ClientRectangle.Height - p.Height;
                    p.Left = cmdbox.TextLength * 8;
                    p.Focus();
                    string[] prms = MiscCoreFuncts.split(cmdbox.Text + " ", false);
                    p.cmdtext = prms;
                    if (prms.Length > 0 && Program.loaded.paramcompleter.ContainsKey(prms[0].ToUpper(CultureInfo.CurrentCulture)))
                    {
                        p.autocompitems = Program.loaded.paramcompleter[prms[0].ToUpper(CultureInfo.CurrentCulture)];
                    }
                    p.Show();
                    p.BringToFront();
                }
                else
                {
                    HistroyWin.Top = this.ClientRectangle.Height - HistroyWin.Height - cmdbox.Height;
                    HistroyWin.Left = 0;
                    HistroyWin.Width = cmdbox.Width;
                    HistroyWin.Show();
                    HistroyWin.BringToFront();
                }
            }
            else
            {
                if (HistroyWin.Visible) HistroyWin.Visible = false;
            }
        }

        private void ConsoleQMenuAction(object sender, EventArgs e)
        {
            ToolStripMenuItem it = (ToolStripMenuItem)sender;
            switch (it.Name)
            {
                case "Copy":
                    this.Consoletext.Copy();
                    break;
                case "Select":
                    this.Consoletext.SelectAll();
                    break;
            }
        }

        public void InsertTextIntoInput(string txt)
        {
            string insert = this.cmdbox.Text += txt;
            this.cmdbox.Clear();
            this.cmdbox.Text = insert;
        }

        private void ConsoleFrm_Shown(object sender, EventArgs e)
        {
            this.Consoletext.Rtf = Resources.logo;
            this.Consoletext.Font = Settings.Default.ConsoleFont;
            #if DEBUG
                this.WriteLine("!!Debug version!!");
            #endif
        }
    }
}